package fhq.hcmute.edu.vn.gestures;

import android.view.MotionEvent;

/**
 * @author Hien Nguyen Oct 23, 2012
 */
public class TouchManager {
	private final TouchPoint[] previousTouchPoints;
	private final TouchPoint[] currentTouchPoints;
	private final TouchPoint[] fixedTouchPoints;
	private final int maxNumberOfTouchPoints = 2;
	private MotionEvent motionEvent;
	private int action = 0;

	public TouchManager() {
		previousTouchPoints = new TouchPoint[maxNumberOfTouchPoints];
		currentTouchPoints = new TouchPoint[maxNumberOfTouchPoints];
		fixedTouchPoints = new TouchPoint[maxNumberOfTouchPoints];
	}

	public MotionEvent getMotionEvent() {
		return motionEvent;
	}

	public void setMotionEvent(MotionEvent motionEvent) {
		this.motionEvent = motionEvent;
	}

	public final TouchPoint getFixedTouchPointAt(int index) {
		if (fixedTouchPoints[index] != null) {
			return fixedTouchPoints[index];
		}
		return new TouchPoint();
	}

	public final TouchPoint getCurrentTouchPointAt(int index) {
		if (currentTouchPoints[index] != null) {
			return currentTouchPoints[index];
		}
		return new TouchPoint();
	}

	public final TouchPoint getPreviousTouchPointAt(int index) {
		if (previousTouchPoints[index] != null) {
			return previousTouchPoints[index];
		}
		return new TouchPoint();
	}

	private final TouchPoint getTouchPoint(TouchPoint a, TouchPoint b) {
		if (a == null || b == null) {
			return new TouchPoint();
		}
		return TouchPoint.subtract(a, b);
	}

	public final TouchPoint getCurrentTouchPoint() {
		return getTouchPoint(currentTouchPoints[0], currentTouchPoints[1]);
	}

	public final TouchPoint getFixedTouchPoint() {
		return getTouchPoint(fixedTouchPoints[0], fixedTouchPoints[1]);
	}

	public final TouchPoint getPreviousTouchPoint() {
		if (previousTouchPoints[0] == null
				|| previousTouchPoints[1] == null) {
			return getTouchPoint(currentTouchPoints[0], currentTouchPoints[1]);
		} else {
			return getTouchPoint(previousTouchPoints[0],
					previousTouchPoints[1]);
		}
	}

	public final float getXMove(int index) {
		if (previousTouchPoints[index] != null) {
			return Math.abs(currentTouchPoints[index].getX()
					- previousTouchPoints[index]
							.getX());
		}
		return 0;
	}

	public final float getYMove(int index) {
		if (previousTouchPoints[index] != null) {
			return Math.abs(currentTouchPoints[index].getY()
					- previousTouchPoints[index]
							.getY());
		}
		return 0;
	}

	public final int getPressCount() {
		int count = 0;
		for (TouchPoint point : currentTouchPoints) {
			if (point != null) {
				++count;
			}
		}
		return count;
	}

	public int getAction() {
		return this.action;
	}

	public final void updateTouchPoints(MotionEvent event) {
		this.motionEvent = event;
		int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
		if (actionCode == MotionEvent.ACTION_DOWN
				|| actionCode == MotionEvent.ACTION_POINTER_DOWN) {
			// reset array if we have two fingers.
			this.action = MotionEvent.ACTION_DOWN;
			if (event.getPointerCount() == maxNumberOfTouchPoints) {
				fixedTouchPoints[0] = null;
				fixedTouchPoints[1] = null;
			}
			for (int i = 0; i < maxNumberOfTouchPoints; ++i) {
				if (i < event.getPointerCount()) {
					int id = event.getPointerId(i);
					if (id >= event.getPointerCount() && id > 0) {
						id--;
					}
					TouchPoint newPoint =
							new TouchPoint(event.getX(i), event.getY(i));
					if (fixedTouchPoints[id] == null) {
						fixedTouchPoints[id] = newPoint;
					}
				}
			}
		} else if (actionCode == MotionEvent.ACTION_POINTER_UP
				|| actionCode == MotionEvent.ACTION_UP) {
			this.action = MotionEvent.ACTION_UP;
			int index =
					(event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
					>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			int id = event.getPointerId(index);
			if (id >= event.getPointerCount() && id > 0) {
				id--;
			}
			fixedTouchPoints[id] = null;
			previousTouchPoints[id] = null;
			currentTouchPoints[id] = null;
		} else if (actionCode == MotionEvent.ACTION_MOVE) {
			this.action = MotionEvent.ACTION_MOVE;
			for (int i = 0; i < maxNumberOfTouchPoints; ++i) {
				if (i < event.getPointerCount()) {
					int id = event.getPointerId(i);
					if (id >= event.getPointerCount() && id > 0) {
						id--;
					}
					TouchPoint newPoint =
							new TouchPoint(event.getX(i), event.getY(i));
					if (currentTouchPoints[id] == null) {
						currentTouchPoints[id] = newPoint;
					} else {
						if (previousTouchPoints[id] != null) {
							previousTouchPoints[id].set(currentTouchPoints[id]);
						} else {
							previousTouchPoints[id] =
									new TouchPoint(newPoint);
						}
						currentTouchPoints[id].set(newPoint);
					}

				} else {
					previousTouchPoints[i] = null;
					currentTouchPoints[i] = null;
				}
			}

		}
	}
}
